<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Symfony\Component\Process\Process;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;

class OmrController extends Controller
{
    /**
     * Return an ordered list of Python executables to try.
     * Priority:
     * 1. .env OMR_PYTHON if set
     * 2. project venv at ./venv/bin/python
     * 3. project venv at ./.venv/bin/python
     * 4. several common system paths
     */
    private function getPythonBins()
    {
        $bins = [];

        $envBin = env('OMR_PYTHON');
        if ($envBin) {
            $bins[] = $envBin;
        }

        // Prefer a project-local virtualenv (venv or .venv)
        $projectVenv = base_path('venv' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'python');
        $dotVenv = base_path('.venv' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'python');
        $bins[] = $projectVenv;
        $bins[] = $dotVenv;

        // Common system paths as fallback
        $bins = array_merge($bins, [
            '/opt/homebrew/Caskroom/miniconda/base/bin/python',
            '/usr/bin/python3',
            'python3',
            'python',
        ]);

        // Remove duplicates while preserving order
        $seen = [];
        $unique = [];
        foreach ($bins as $b) {
            if (!$b)
                continue;
            if (!in_array($b, $seen, true)) {
                $seen[] = $b;
                $unique[] = $b;
            }
        }

        return $unique;
    }
    /**
     * 接收前端数据，调用 Python 脚本生成 OMR 答题卡，并返回文件下载流。
     */
    public function generateOmrCard(Request $request)
    {
        // 验证输入
        $data = $request->validate([
            'testName' => 'required|string',
            'omrSheets' => 'required|array',
        ]);

        $testName = $data['testName'];

        // 临时目录准备（storage/app/temp）
        $tempDir = 'temp';
        Storage::makeDirectory($tempDir);
        $tempDirPath = Storage::path($tempDir);

        $jsonFileName = "omr_input_" . time() . ".json";
        $jsonFilePath = Storage::path("{$tempDir}/{$jsonFileName}");

        // 写入 JSON（保留中文编码）
        File::put($jsonFilePath, json_encode($data, JSON_UNESCAPED_UNICODE));

        // Python 脚本路径
        $pythonScriptPath = base_path('resources/code/omr_circle_generator.py');

        // 尝试使用 python3；若失败再尝试 python（部分环境）
        // 优先尝试完整的Python路径 (conda 环境)
        $pythonBins = $this->getPythonBins();

        $processOutput = null;
        $processError = null;
        $process = null;
        $generatedFilePath = null;
        foreach ($pythonBins as $bin) {
            $process = new Process([
                $bin,
                $pythonScriptPath,
                '--input_json',
                $jsonFilePath,
                '--output_dir',
                $tempDirPath,
            ]);
            // 设置合理超时时间（秒）
            $process->setTimeout(120);

            try {
                $process->run();
            } catch (\Throwable $e) {
                Log::warning("执行 Python ($bin) 时发生异常: " . $e->getMessage());
                continue;
            }

            $processOutput = $process->getOutput();
            $processError = $process->getErrorOutput();

            if ($process->isSuccessful()) {
                // 成功则停止尝试其它 python 可执行文件
                break;
            } else {
                Log::warning("Python ($bin) 执行失败，错误输出: " . $processError);
            }
        }

        // 如果都失败
        if (!$process || !$process->isSuccessful() || !isset($processOutput) || trim($processOutput) === '') {
            // 清理临时输入文件
            File::delete($jsonFilePath);

            Log::error('OMR 生成脚本未返回任何输出或全部执行失败。最后一次错误：' . ($processError ?? ''));
            return response()->json([
                'message' => '生成答题卡失败：无法执行 Python 脚本或脚本未产生输出。'
            ], 500);
        }

        // 尝试从脚本输出中解析出生成文件路径
        // 使用更严格的正则表达式匹配文件路径（以 / 或 . 开头的路径，以 .png 结尾）
        $outputLines = array_filter(explode("\n", trim($processOutput)));
        $generatedFilePath = null;

        foreach (array_reverse($outputLines) as $line) {
            // 改进的正则表达式：匹配绝对路径（/开头）或相对路径
            if (preg_match('/\/[^\s]*\.png$/', trim($line), $matches)) {
                $generatedFilePath = trim($matches[0]);
                break;
            }
        }

        // 如果还是没找到，尝试更宽松的匹配（处理相对路径情况）
        if (!$generatedFilePath) {
            foreach (array_reverse($outputLines) as $line) {
                if (preg_match('/[^\s:]+\.png/', trim($line), $matches)) {
                    $generatedFilePath = trim($matches[0]);
                    break;
                }
            }
        }

        if (!$generatedFilePath) {
            Log::error('无法从 Python 输出中解析 PNG 路径，输出内容：' . $processOutput);
            File::delete($jsonFilePath);
            return response()->json([
                'message' => '生成成功，但无法定位生成文件路径（脚本输出无法解析）。'
            ], 500);
        }

        // 确认文件存在
        if (!File::exists($generatedFilePath)) {
            Log::error('生成的 OMR 文件未找到: ' . $generatedFilePath . '，脚本输出：' . $processOutput);
            File::delete($jsonFilePath);
            return response()->json([
                'message' => '生成的 OMR 文件未找到（脚本返回的路径不存在）。'
            ], 500);
        }

        // 清理临时输入文件（保留生成文件，交由 deleteFileAfterSend 清理）
        File::delete($jsonFilePath);

        // 返回下载，发送后删除生成文件（deleteFileAfterSend 由框架支持）
        try {
            return response()->download($generatedFilePath, basename($generatedFilePath))
                ->deleteFileAfterSend(true);
        } catch (\Throwable $e) {
            Log::error('返回下载响应失败: ' . $e->getMessage());
            return response()->json([
                'message' => '生成答题卡成功，但无法发送文件下载。'
            ], 500);
        }
    }

    /**
     * 上传 OMR 图像并保存到项目根目录的 omr_output 文件夹
     * 接收字段: testName, studentId, omrFile (multipart file)
     */
    public function uploadOmrImage(Request $request)
    {
        $data = $request->validate([
            'testName' => 'required|string',
            'studentId' => 'required|string',
            'omrFile' => 'required|file|mimes:png,jpg,jpeg',
        ]);

        $file = $request->file('omrFile');
        $testName = $data['testName'];
        $studentId = $data['studentId'];

        $destDir = base_path('omr_output');
        if (!File::exists($destDir)) {
            File::makeDirectory($destDir, 0755, true);
        }

        $extension = $file->getClientOriginalExtension() ?: 'png';
        $filename = "omr_{$testName}_{$studentId}.{$extension}";
        $fullPath = $destDir . DIRECTORY_SEPARATOR . $filename;

        try {
            $file->move($destDir, $filename);
        } catch (\Throwable $e) {
            Log::error('OMR 文件保存失败: ' . $e->getMessage());
            return response()->json(['message' => '保存失败', 'error' => $e->getMessage()], 500);
        }

        return response()->json(['message' => 'uploaded', 'path' => $fullPath]);
    }

    /**
     * 调用 process_omr.py 对指定的 omr image 进行识别并返回终端输出以及可视化图片路径
     * 接收字段: testName, studentId
     */
    public function processOmr(Request $request)
    {
        $data = $request->validate([
            'testName' => 'required|string',
            'studentId' => 'required|string',
        ]);

        $testName = $data['testName'];
        $studentId = $data['studentId'];

        $imagePath = base_path("omr_output/omr_{$testName}_{$studentId}.png");
        if (!File::exists($imagePath)) {
            return response()->json(['message' => 'OMR 图片未找到: ' . $imagePath], 404);
        }

        $keyPath = base_path("resources/asset/{$testName}_key.json");
        if (!File::exists($keyPath)) {
            return response()->json(['message' => 'Key JSON 未找到: ' . $keyPath], 404);
        }

        $pythonScriptPath = base_path('resources/code/process_omr.py');

        $pythonBins = $this->getPythonBins();

        $processOutput = null;
        $processError = null;
        $process = null;

        foreach ($pythonBins as $bin) {
            $process = new Process([
                $bin,
                $pythonScriptPath,
                '--image',
                $imagePath,
                '--key',
                $keyPath,
                '--output-dir',
                base_path('results'),
            ]);
            // 识别可能需要更长时间
            $process->setTimeout(300);

            try {
                $process->run();
            } catch (\Throwable $e) {
                Log::warning("执行 Python ($bin) 时发生异常: " . $e->getMessage());
                continue;
            }

            $processOutput = $process->getOutput();
            $processError = $process->getErrorOutput();

            if ($process->isSuccessful()) {
                break;
            } else {
                Log::warning("Python ($bin) 执行失败，错误输出: " . $processError);
            }
        }

        if (!$process || !$process->isSuccessful()) {
            Log::error('OMR 识别脚本执行失败。最后一次错误：' . ($processError ?? ''));
            return response()->json(['message' => '识别失败', 'error' => $processError ?? 'no output'], 500);
        }

        // 构建可视化图片路径（前端可直接访问，如果服务器允许公开 results 目录）
        // 使用 rawurlencode 对文件名进行编码，确保 URL 在包含空格或非 ASCII 字符时也能安全访问
        $baseName = pathinfo($imagePath, PATHINFO_FILENAME);
        $vizFilename = "visualization_{$baseName}.png";
        $resultsJsonFilename = "results_{$baseName}.json";

        $vizPath = '/results/' . rawurlencode($vizFilename);
        $resultJsonPath = '/results/' . rawurlencode($resultsJsonFilename);

        return response()->json([
            'output' => $processOutput,
            'error' => $processError,
            'visualization' => $vizPath,
            'results_json' => $resultJsonPath,
        ]);
    }
}
